#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Label:
	""" ラベルオブジェクト """
	def __init__(self, name, location, filename, lineno):
		self.name     = name
		self.location = location
		self.filename = filename
		self.lineno   = lineno
	def getLocation(self):
		return self.location
	def getName(self):
		return self.name

class Writer:
	BYTE = 1 # 1byte
	WORD = 2 # 2byte
	LONG = 4 # 4byte
	""" スクリプト書き込みオブジェクト """
	def __init__(self, filepath, parser):
		self.f       = open(filepath, "wb")
		self.parser  = parser
		self.address = 0
		self.log     = open(filepath + ".log", "w")
		self.writeLogEx("## log begin ##")
		self.labels      = {} # 本当のラベル（ディクショナリ）
		self.labelsProto = [] # 仮のラベル（リスト）
	def writeByte(self, b):
		self.f.write("%c"%b)
		self.address += self.BYTE
	def writeWord(self, word):
		iTmp = word
		for i in range(self.WORD-1, -1, -1):
			c = iTmp >> (8*i)
			self.f.write("%c"%c)
			iTmp = iTmp - (c << (8*i))
		self.address += self.WORD
	def writeLong(self, long):
		iTmp = long
		for i in range(self.LONG-1, -1, -1):
			c = iTmp >> (8*i)
			self.f.write("%c"%c)
			iTmp = iTmp - (c << (8*i))
		self.address += self.LONG
	def writeLongEx(self, address, long):
		""" 指定アドレスに４バイト書き込み """
		self.f.seek(address, 0) # 絶対値のアドレスに移動
		self.address = address
		self.writeLong(long)
	def writeAddress(self):
		""" 現在のアドレスを書き込む """
		self.writeLong(self.address)
	def writeString(self, string):
		""" 文字列の書き込み """
		self.f.write(string)
		self.address += len(string)
	def writeLog(self, msg):
		""" ログの書き込み """
		self.log.write("%08x :%s\n"%(self.address, msg))
	def writeLogEx(self, msg):
		""" ログの書き込み２ """
		self.log.write(msg+"\n")
	def finalize(self):
		""" 終了処理 """
		self.patchLabel()
		
		self.f.close()
		self.log.close()
	def getLocalLabel(self):
		""" ローカルラベルの名称を生成 """
		return "##%08x##"%len(self.labelsProto)
		
	def writeLabelProto(self):
		""" 仮ラベル追加 """
		name = self.getLocalLabel()
		self.writeLabelProtoEx(name)
		return name
	def writeLabelProtoEx(self, name):
		""" 仮ラベルを名前を指定して書き込み """
		label = Label(
			name,
			self.address,
			self.parser.lexer.getFinename(),
			self.parser.lexer.getLineno())
		self.labelsProto.append(label)
		self.writeLong(0xdead) # 仮登録
	def writeLabel(self, name):
		""" 本ラベル追加 """
		label = Label(
			name,
			self.address,
			self.parser.lexer.getFinename(),
			self.parser.lexer.getLineno())
		if self.labels.has_key(name):
			raise "Duplicate label: %s"%name
		self.labels[name] = label
		# ラベルに実体はないので書き込まない
	def patchLabel(self):
		""" ラベルのパッチ当て """
		self.writeLogEx("")
		self.writeLogEx("## patchLabel begin ## 'proto' <-- 'real'")
		for proto in self.labelsProto:
			if self.labels.has_key(proto.getName()):
				name = proto.getName()
				locProto = proto.getLocation()
				locReal  = self.labels[name].getLocation()
				self.writeLongEx(locProto, locReal)
				self.writeLogEx("  '%s': [%08d] <-- [%08d]"%(name, locProto, locReal))
			else:
				raise "None label:%s"%proto.getName()
		self.writeLogEx("## patchLabel end ##")
		